/****************************************************************************
** Copyright (c) quickfixengine.org  All rights reserved.
**
** This file is part of the QuickFIX FIX Engine
**
** This file may be distributed under the terms of the quickfixengine.org
** license as defined by quickfixengine.org and appearing in the file
** LICENSE included in the packaging of this file.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.quickfixengine.org/LICENSE for licensing information.
**
** Contact ask@quickfixengine.org if any conditions of this licensing are
** not clear to you.
**
****************************************************************************/

#ifdef _MSC_VER
#include "stdafx.h"
#else
#include "config.h"
#endif
#include "CallStack.h"

#include "DataDictionary.h"
#include "Message.h"
#include <fstream>
#include <memory>

#ifdef HAVE_LIBXML
#include "LIBXML_DOMDocument.h"
#elif _MSC_VER
#include "MSXML_DOMDocument.h"
#else
#include "LIBXML_DOMDocument.h"
#endif

#ifdef _MSC_VER
#define RESET_AUTO_PTR(OLD, NEW) OLD = NEW;
#else
#define RESET_AUTO_PTR(OLD, NEW) OLD.reset( NEW.release() );
#endif

namespace FIX
{
DataDictionary::DataDictionary()
: m_hasVersion( false ), m_checkFieldsOutOfOrder( true ),
  m_checkFieldsHaveValues( true ), m_checkUserDefinedFields( true ),
  m_orderedFieldsArray(0) {}

DataDictionary::DataDictionary( std::istream& stream )
throw( ConfigError )
: m_hasVersion( false ), m_checkFieldsOutOfOrder( true ),
  m_checkFieldsHaveValues( true ), m_checkUserDefinedFields( true ),
  m_orderedFieldsArray(0)
{
  readFromStream( stream );
}

DataDictionary::DataDictionary( const std::string& url )
throw( ConfigError )
: m_hasVersion( false ), m_checkFieldsOutOfOrder( true ),
  m_checkFieldsHaveValues( true ), m_checkUserDefinedFields( true ),
  m_orderedFieldsArray(0)
{
  readFromURL( url );
}

DataDictionary::DataDictionary( const DataDictionary& copy )
{
  *this = copy;
}

DataDictionary::~DataDictionary()
{
  FieldToGroup::iterator i;
  for ( i = m_groups.begin(); i != m_groups.end(); ++i )
    delete i->second.second;
  if( m_orderedFieldsArray )
    delete [] m_orderedFieldsArray;
}

DataDictionary& DataDictionary::operator=( const DataDictionary& rhs )
{ QF_STACK_PUSH(DataDictionary::operator=)

  m_hasVersion = rhs.m_hasVersion;
  m_checkFieldsOutOfOrder = rhs.m_checkFieldsOutOfOrder;
  m_checkFieldsHaveValues = rhs.m_checkFieldsHaveValues;
  m_checkUserDefinedFields = rhs.m_checkUserDefinedFields;
  m_beginString = rhs.m_beginString;
  m_messageFields = rhs.m_messageFields;
  m_requiredFields = rhs.m_requiredFields;
  m_messages = rhs.m_messages;
  m_fields = rhs.m_fields;
  m_orderedFields = rhs.m_orderedFields;
  m_orderedFieldsArray = 0;
  m_headerFields = rhs.m_headerFields;
  m_trailerFields = rhs.m_trailerFields;
  m_fieldTypes = rhs.m_fieldTypes;
  m_fieldValues = rhs.m_fieldValues;
  m_fieldNames = rhs.m_fieldNames;
  m_names = rhs.m_names;
  m_valueNames = rhs.m_valueNames;

  FieldToGroup::const_iterator i = rhs.m_groups.begin();
  for ( ; i != rhs.m_groups.end(); ++i )
  {
    addGroup( i->first.first, i->first.second,
              i->second.first, *i->second.second );
  }
  m_Message2TemplateId = rhs.m_Message2TemplateId;
  m_TemplateId2Message = rhs.m_TemplateId2Message;
  m_SortedFieldValues = rhs.m_SortedFieldValues;
  return *this;

  QF_STACK_POP
}

void DataDictionary::validate( const Message& message )
throw( std::exception )
{ QF_STACK_PUSH(DataDictionary::validate)

  const Header& header = message.getHeader();
  const BeginString& beginString = FIELD_GET_REF( header, BeginString );
  const MsgType& msgType = FIELD_GET_REF( header, MsgType );

  std::string ddBeginString = getVersion();
  if ( m_hasVersion && m_beginString != beginString )
    throw UnsupportedVersion();

  int field = 0;
  if ( m_checkFieldsOutOfOrder && !message.hasValidStructure(field) )
    throw TagOutOfOrder(field);

  if ( m_hasVersion )
  {
    checkMsgType( msgType );
    checkHasRequired( message.getHeader(), message, message.getTrailer(), msgType );
  }

  iterate( message.getHeader(), msgType );
  iterate( message.getTrailer(), msgType );
  iterate( message, msgType );

  QF_STACK_POP
}

void DataDictionary::iterate( const FieldMap& map, const MsgType& msgType )
{ QF_STACK_PUSH(DataDictionary::iterate)

  int lastField = 0;

  FieldMap::iterator i;
  for ( i = map.begin(); i != map.end(); ++i )
  {
    const FieldBase& field = i->second;
    if( i != map.begin() && (field.getField() == lastField) )
      throw RepeatedTag( lastField );
    checkHasValue( field );

    if ( m_hasVersion )
    {
      checkValidFormat( field );
      checkValue( field );
    }

    if ( m_beginString.getValue().length() && shouldCheckTag(field) )
    {
      checkValidTagNumber( field );
      if ( !Message::isHeaderField( field, this )
           && !Message::isTrailerField( field, this ) )
      {
        checkIsInMessage( field, msgType );
        checkGroupCount( field, map, msgType );
      }
    }
    lastField = field.getField();
  }

  QF_STACK_POP
}

void DataDictionary::readFromURL( const std::string& url )
throw( ConfigError )
{ QF_STACK_PUSH(DataDictionary::readFromURL)
  try
  {
	  try
	  {
		#ifdef HAVE_LIBXML
		  DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
		#elif _MSC_VER
		  DOMDocumentPtr pDoc = DOMDocumentPtr(new MSXML_DOMDocument());
		#else
		  DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
		#endif

		  if(!pDoc->load(url))
			throw ConfigError(url + ": Could not parse data from fix dictionary file");
			  readFromDocument( pDoc );
	  }
	  catch ( ConfigError& e )
	  {
		  try
		  {
			#ifdef HAVE_LIBXML
			  DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
			#elif _MSC_VER
			  DOMDocumentPtr pDoc = DOMDocumentPtr(new MSXML_DOMDocument());
			#else
			  DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
			#endif

			  if(!pDoc->load(url))
				throw ConfigError(url + ": Could not parse data from fast dictionary file");
			  pDoc->removeComments(); //try to FAST template format
			  readFromFASTDocument( pDoc );
		  }
		  catch( ConfigError& e )
		  {
			throw ConfigError( url + ": " + e.what() );
		  }
		  catch( Exception& e )
		  {
			throw ConfigError( url + ": " + e.what() );
		  }
			  }
  }
  catch( ConfigError& e )
  {
    throw ConfigError( url + ": " + e.what() );
  }
  catch( Exception& e )
  {
    throw ConfigError( url + ": " + e.what() );
  }


  QF_STACK_POP
}

void DataDictionary::readFromStream( std::istream& stream )
throw( ConfigError )
{ QF_STACK_PUSH(DataDictionary::readFromStream)

	try
	{

	#ifdef HAVE_LIBXML
	  DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
	#elif _MSC_VER
	  DOMDocumentPtr pDoc = DOMDocumentPtr(new MSXML_DOMDocument());
	#else
	  DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
	#endif
		  if(!pDoc->load(stream))
			throw ConfigError("Could not parse data from fix dictionary stream");
		  readFromDocument( pDoc );
	}
	  catch ( ConfigError& e )
	  {
		#ifdef HAVE_LIBXML
		  DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
		#elif _MSC_VER
		  DOMDocumentPtr pDoc = DOMDocumentPtr(new MSXML_DOMDocument());
		#else
		  DOMDocumentPtr pDoc = DOMDocumentPtr(new LIBXML_DOMDocument());
		#endif
		  if(!pDoc->load(stream))
			  throw ConfigError("Could not parse data from fast dictionary stream");		  
		  pDoc->removeComments(); //try to FAST template format
		  readFromFASTDocument( pDoc );
	  }

  QF_STACK_POP
}

void DataDictionary::readFromDocument( DOMDocumentPtr pDoc )
throw( ConfigError )
{ QF_STACK_PUSH(DataDictionary::readFromDocument)


  // VERSION
  DOMNodePtr pFixNode = pDoc->getNode("/fix");
  if(!pFixNode.get())
    throw ConfigError("Could not parse data dictionary file"
                      ", or no <fix> node found at root");
  DOMAttributesPtr attrs = pFixNode->getAttributes();
  std::string base;
  if(!attrs->get("base", base))
    throw ConfigError("base attribute not found on <fix>");

  std::string major;
  if(!attrs->get("major", major))
    throw ConfigError("major attribute not found on <fix>");
  std::string minor;
  if(!attrs->get("minor", minor))
    throw ConfigError("minor attribute not found on <fix>");
  setVersion(base + major + "." + minor);

  // FIELDS
  DOMNodePtr pFieldsNode = pDoc->getNode("/fix/fields");
  if(!pFieldsNode.get())
    throw ConfigError("<fields> section not found in data dictionary");

  DOMNodePtr pFieldNode = pFieldsNode->getFirstChildNode();
  if(!pFieldNode.get()) throw ConfigError("No fields defined");

  while(pFieldNode.get())
  {
    if(pFieldNode->getName() == "field")
    {
      DOMAttributesPtr attrs = pFieldNode->getAttributes();
      std::string name;
      if(!attrs->get("name", name))
        throw ConfigError("<field> does not have a name attribute");

      std::string number;
      if(!attrs->get("number", number))
        throw ConfigError("<field> " + name + " does not have a number attribute");
      int num = atol(number.c_str());
      std::string type;
      if(!attrs->get("type", type))
        throw ConfigError("<field> " + name + " does not have a type attribute");
      addField(num);
      addFieldType(num, XMLTypeToType(type));
      addFieldName(num, name);

      DOMNodePtr pFieldValueNode = pFieldNode->getFirstChildNode();
      while(pFieldValueNode.get())
      {
        if(pFieldValueNode->getName() == "value")
        {
          DOMAttributesPtr attrs = pFieldValueNode->getAttributes();
          std::string enumeration;
          if(!attrs->get("enum", enumeration))
            throw ConfigError("<value> does not have enum attribute in field " + name);
          addFieldValue(num, enumeration);
          std::string description;
          if(attrs->get("description", description))
            addValueName(num, enumeration, description);
        }
        RESET_AUTO_PTR(pFieldValueNode, pFieldValueNode->getNextSiblingNode());
      }
    }
    RESET_AUTO_PTR(pFieldNode, pFieldNode->getNextSiblingNode());
  }

  int headerSlot = 0;
  // HEADER
  DOMNodePtr pHeaderNode = pDoc->getNode("/fix/header");
  if(!pHeaderNode.get())
    throw ConfigError("<header> section not found in data dictionary");

  DOMNodePtr pHeaderFieldNode = pHeaderNode->getFirstChildNode();
  if(!pHeaderFieldNode.get()) throw ConfigError("No header fields defined");

  std::stringstream htid;
  htid << eFAST_HDR_TEMPLATE;
  addMsgType(htid.str());
  addTemplateID(htid.str(), eFAST_HDR_TEMPLATE);

  while(pHeaderFieldNode.get())
  {
    if(pHeaderFieldNode->getName() == "field" || pHeaderFieldNode->getName() == "group" )
    {
      DOMAttributesPtr attrs = pHeaderFieldNode->getAttributes();
      std::string name;
      if(!attrs->get("name", name))
        throw ConfigError("<field> does not have a name attribute");

          std::string required = "Y";
          bool isRequired = true;
      if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

          addHeaderField(lookupXMLFieldNumber(pDoc.get(), name), isRequired);

          std::string value="";
      if ( !attrs->get("value", value) )
                  value = "none";

          std::string ref = "";
          if ( !attrs->get("ref", ref) )
                  ref = "none";

          std::string _operator = "";
      if ( !attrs->get("operator", _operator) )
                  _operator = "none";

          int num = lookupXMLFieldNumber(pDoc.get(), name);

          eFAST_TYPE FastType;
          getFieldType(num, FastType);
          eFAST_OP FastOperator;
          getFieldOpearator(_operator, FastOperator);
          FastTag ft(FastType, isRequired, FastOperator, eFAST_HDR_TEMPLATE, headerSlot , num, value, ref, name);
          addMsgFieldTag(ft);
          headerSlot++;

    }
    if(pHeaderFieldNode->getName() == "group")
    {
      DOMAttributesPtr attrs = pHeaderFieldNode->getAttributes();
      std::string required = "Y";
          bool isRequired = true;
      if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

          addXMLGroup(pDoc.get(), pHeaderFieldNode.get(), "_header_", *this, isRequired);
    }

    RESET_AUTO_PTR(pHeaderFieldNode, pHeaderFieldNode->getNextSiblingNode());
  }

  // TRAILER
  int trailerSlot = 0;
  DOMNodePtr pTrailerNode = pDoc->getNode("/fix/trailer");
  if(!pTrailerNode.get())
    throw ConfigError("<trailer> section not found in data dictionary");

  DOMNodePtr pTrailerFieldNode = pTrailerNode->getFirstChildNode();
  if(!pTrailerFieldNode.get()) throw ConfigError("No trailer fields defined");

  std::stringstream ttid;
  ttid << eFAST_TRL_TEMPLATE;
  addMsgType(ttid.str());
  addTemplateID(ttid.str(), eFAST_TRL_TEMPLATE);

  while(pTrailerFieldNode.get())
  {
    if(pTrailerFieldNode->getName() == "field" || pTrailerFieldNode->getName() == "group" )
    {
      DOMAttributesPtr attrs = pTrailerFieldNode->getAttributes();
      std::string name;
      if(!attrs->get("name", name))
        throw ConfigError("<field> does not have a name attribute");
      std::string required = "Y";
          bool isRequired = true;
      if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

          addTrailerField(lookupXMLFieldNumber(pDoc.get(), name), isRequired);

          std::string value="";
      if ( !attrs->get("value", value) )
                  value = "none";

          std::string ref = "";
          if ( !attrs->get("ref", ref) )
                  ref = "none";

          std::string _operator = "";
      if ( !attrs->get("operator", _operator) )
                  _operator = "none";


          int num = lookupXMLFieldNumber(pDoc.get(), name);

          eFAST_TYPE FastType;
          getFieldType(num, FastType);
          eFAST_OP FastOperator;
          getFieldOpearator(_operator, FastOperator);
          FastTag ft(FastType, isRequired, FastOperator, eFAST_TRL_TEMPLATE, trailerSlot , num, value, ref, name);
          addMsgFieldTag(ft);
          trailerSlot++;

    }
    if(pTrailerFieldNode->getName() == "group")
    {
      DOMAttributesPtr attrs = pTrailerFieldNode->getAttributes();
      std::string required = "Y";
          bool isRequired = true;
      if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

          addXMLGroup(pDoc.get(), pTrailerFieldNode.get(), "_trailer_", *this, isRequired);
    }

    RESET_AUTO_PTR(pTrailerFieldNode, pTrailerFieldNode->getNextSiblingNode());
  }

  // MSGTYPE
  DOMNodePtr pMessagesNode = pDoc->getNode("/fix/messages");
  if(!pMessagesNode.get())
    throw ConfigError("<messages> section not found in data dictionary");

  DOMNodePtr pMessageNode = pMessagesNode->getFirstChildNode();
  if(!pMessageNode.get()) throw ConfigError("No messages defined");

  while(pMessageNode.get())
  {
    if(pMessageNode->getName() == "message")
    {
          int fieldSlot = 0;

      DOMAttributesPtr attrs = pMessageNode->getAttributes();
      std::string msgtype;
          std::string tid;
      if(!attrs->get("msgtype", msgtype))
        throw ConfigError("<field> does not have a name attribute");
      addMsgType(msgtype);

          if(attrs->get("tid", tid))
                  addTemplateID(msgtype, atoi(tid.c_str()));

      std::string name;
      if(attrs->get("name", name))
        addValueName( 35, msgtype, name );

      DOMNodePtr pMessageFieldNode = pMessageNode->getFirstChildNode();
      if( !pMessageFieldNode.get() )
          {
        throw ConfigError("<message> contains no fields");
          }
      while( pMessageFieldNode.get() )
      {
        if(pMessageFieldNode->getName() == "field"
           || pMessageFieldNode->getName() == "group")
        {
          DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
          std::string name;
          if(!attrs->get("name", name))
            throw ConfigError("<field> does not have a name attribute");

          int num = lookupXMLFieldNumber(pDoc.get(), name);
          addMsgField(msgtype, num);

                  std::string value="";
                  if ( !attrs->get("value", value) )
                          value = "none";

                  std::string _operator = "";
                  if ( !attrs->get("operator", _operator) )
                          _operator = "none";

                  std::string ref = "";
                  if ( !attrs->get("ref", ref) )
                          ref = "none";

                  std::string required = "Y";
                  bool isRequired = true;
                  if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

          if( isRequired )
          {
            addRequiredField(msgtype, num);
          }
                  eFAST_TYPE FastType;
                  getFieldType(num, FastType);
                  eFAST_OP FastOperator;
                  getFieldOpearator(_operator, FastOperator);
                  FastTag ft(FastType, isRequired, FastOperator, atoi(tid.c_str()), fieldSlot , num, value, ref, name);
                  addMsgFieldTag(ft);
                  fieldSlot++;
        }
        else if(pMessageFieldNode->getName() == "component")
        {
          DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
                  std::string required = "Y";
                  bool isRequired = false;
                  if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;
          addXMLComponentFields(pDoc.get(), pMessageFieldNode.get(),
                                msgtype, *this, isRequired);
        }
        if(pMessageFieldNode->getName() == "group")
        {

          DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
                  std::string required = "Y";
                  bool isRequired = true;
                  if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

                  std::string gtid;
                  if(attrs->get("tid", gtid) && m_TemplateId2Message.find(atoi(gtid.c_str())) == m_TemplateId2Message.end())
                  {
                          addTemplateID(gtid, atoi(gtid.c_str()));
                          addXMLGroup(pDoc.get(), pMessageFieldNode.get(), msgtype, *this, isRequired, atoi(gtid.c_str()) );
                  }
                  else
                          addXMLGroup(pDoc.get(), pMessageFieldNode.get(), msgtype, *this, isRequired );
        }
        RESET_AUTO_PTR(pMessageFieldNode,
                       pMessageFieldNode->getNextSiblingNode());
      }
    }
    RESET_AUTO_PTR(pMessageNode, pMessageNode->getNextSiblingNode());
  }

  QF_STACK_POP
}


/////////////////////////////////////////////////////
void DataDictionary::readFromFASTDocument( DOMDocumentPtr pDoc )
throw( ConfigError )
{ QF_STACK_PUSH(DataDictionary::readFromFASTDocument)


  // VERSION
  DOMNodePtr pFixNode = pDoc->getNode("/templates");
  if(!pFixNode.get())
    throw ConfigError("Could not parse data dictionary file"
                      ", or no <templates> node found at root");
  DOMAttributesPtr attrs = pFixNode->getAttributes();
  std::string xmlns;
 // if(!attrs->get("xmlns", xmlns))
  //  throw ConfigError("xmlns attribute not found on <xmlns>");

  setVersion("1.1");


  DOMNodePtr pMessageNode = pFixNode->getFirstChildNode();
  if(!pMessageNode.get()) throw ConfigError("No messages defined");

  while(pMessageNode.get())
  {
      std::vector<int> requiredFlds;
      std::vector<int> msgFlds;
    if(pMessageNode->getName() == "template")
    {
        requiredFlds.clear();
        msgFlds.clear();
      int fieldSlot = 0;
      bool bMsgTypeFound = false;

      DOMAttributesPtr attrs = pMessageNode->getAttributes();
      std::string tid;

      if(!attrs->get("id", tid))
            throw ConfigError("No templateID defined");

      std::string name;
      if(!attrs->get("name", name))
          throw ConfigError("No message name defined");

      DOMNodePtr pMessageFieldNode = pMessageNode->getFirstChildNode();
      if( !pMessageFieldNode.get() )
          {
        throw ConfigError("<message> contains no fields");
          }

      std::string msgType;

      while( pMessageFieldNode.get() )
      {

       bool bRequired = true;

      if(pMessageFieldNode->getName() != "group"
           && pMessageFieldNode->getName() != "sequence")
        {
            int iField =0;
            AddXMLFASTField(pDoc.get(), pMessageFieldNode.get(), bMsgTypeFound,
                     atoi(tid.c_str()), msgType, bRequired, fieldSlot, *this, iField, name);

            if ( bMsgTypeFound )
            {
               for ( size_t i = 0; i < requiredFlds.size(); i++ )
                {
                    addRequiredField(msgType, requiredFlds[i]);
                }
                requiredFlds.clear();
                for ( size_t t = 0; t < msgFlds.size(); t++ )
                {
                    addMsgField(msgType, msgFlds[t]);
                }
                msgFlds.clear();
               addMsgField(msgType, iField);
            }
            else
            {
                msgFlds.push_back(iField);
            }

            if( bRequired )
            {
              if(bMsgTypeFound)
                addRequiredField(msgType, iField);
              else
                requiredFlds.push_back(iField);
            }
        }
        else if(pMessageFieldNode->getName() == "group")
        {

            ;
            /********************************
          DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
                  std::string required = "Y";
                  bool isRequired = false;
                  if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;
          addXMLComponentFASTFields(pDoc.get(), pMessageFieldNode.get(),
                                msgtype, *this, isRequired);
        ****************************/
        }
        if(pMessageFieldNode->getName() == "sequence")
        {

            addXMLFASTGroup( pDoc.get(), pMessageFieldNode.get(),
                                  msgType,
                                  *this);
        }
        RESET_AUTO_PTR(pMessageFieldNode,
                       pMessageFieldNode->getNextSiblingNode());
      }
    }
    RESET_AUTO_PTR(pMessageNode, pMessageNode->getNextSiblingNode());
  }

  QF_STACK_POP
}
/////////////////////////////////////////////////////



int DataDictionary::AddXMLFASTField(DOMDocument* pDoc, DOMNode* pMessageFieldNode, bool &bMsgTypeFound,
                                     int tid, std::string &msgType, bool &bRequired,
                                     int &fieldSlot, DataDictionary &DD, int &ifield,
                                     const std::string & msgName) throw( ConfigError )
{
     QF_STACK_PUSH(DataDictionary::AddXMLFASTField)

         int unknownMsg = 0;
            DOMAttributesPtr attrs = pMessageFieldNode->getAttributes();
            std::string dataType = pMessageFieldNode->getName();
            if (dataType == "length")
                dataType = "uInt32";
            std::string fldname;
            if(!attrs->get("name", fldname))
                throw ConfigError("<field> does not have a name attribute");

            std::string number;
            if(!attrs->get("id", number))
                throw ConfigError("<field> " + fldname + " does not have a number attribute");
            int num = atol(number.c_str());

            DD.addFASTField(num);
            DD.addFASTFieldType(num, XMLFASTTypeToType(dataType));
            DD.addFASTFieldName(num, fldname);

            addFASTField(num);
            addFASTFieldType(num, XMLFASTTypeToType(dataType));
            addFASTFieldName(num, fldname);
            ifield = num;

          //int num = lookupXMLFieldNumber(pDoc.get(), name);

                  std::string value="none";
                  std::string _operator = "none";
                  std::string ref = "none";
                  std::string required = "mandatory";
                  bRequired = true;
            if (pMessageFieldNode->getName() == "templateRef" )
            {
                if ( !attrs->get("id", ref) )
                          ref = "none";
            }

          if (attrs->get("presence", required))
              (required == "optional" )? bRequired  = false : bRequired  = true;


            DOMNodePtr pMessageFieldOpNode = pMessageFieldNode->getFirstChildNode();
            if( pMessageFieldOpNode.get() )
            {
                _operator = pMessageFieldOpNode->getName();
                DOMAttributesPtr attrsOp = pMessageFieldOpNode->getAttributes();
                attrsOp->get("value", value);
            }

            if ( num == 35 )
            {

                if ( value != "none" )
                    msgType = value;
                else
                {
                    char szTemp[100];
                    sprintf(szTemp, "XYZ%d", unknownMsg++);
                    msgType = szTemp;
                }
                addMsgType(msgType);
                addTemplateID(msgType, tid);
                addValueName( 35, msgType, msgName );
                bMsgTypeFound = true;

            }

                  eFAST_TYPE FastType;
                  getFieldType(num, FastType);
                  eFAST_OP FastOperator;
                  getFieldOpearator(_operator, FastOperator);
                  FastTag ft(FastType, bRequired, FastOperator, tid, fieldSlot , num, value, ref, fldname);
                  addMsgFieldTag(ft);
                  fieldSlot++;

      return fieldSlot;

    QF_STACK_POP
}

int* DataDictionary::getOrderedFields() const
{ QF_STACK_PUSH(DataDictionary::getOrderedFields)

  if( m_orderedFieldsArray ) return m_orderedFieldsArray;
  m_orderedFieldsArray = new int[m_orderedFields.size() + 1];

  int* i = m_orderedFieldsArray;
  OrderedFields::const_iterator iter;
  for( iter = m_orderedFields.begin(); iter != m_orderedFields.end(); *(i++) = *(iter++) ) {}
  *i = 0;
  return m_orderedFieldsArray;

  QF_STACK_POP
}

int DataDictionary::lookupXMLFieldNumber( DOMDocument* pDoc, DOMNode* pNode ) const
{ QF_STACK_PUSH(DataDictionary::lookupXMLFieldNumber)

  DOMAttributesPtr attrs = pNode->getAttributes();
  std::string name;
  if(!attrs->get("name", name))
    throw ConfigError("No name given to field");
  return lookupXMLFieldNumber( pDoc, name );

  QF_STACK_POP
}

int DataDictionary::lookupXMLFieldNumber
( DOMDocument* pDoc, const std::string& name ) const
{ QF_STACK_PUSH(DataDictionary::lookupXMLFieldNumber)

  NameToField::const_iterator i = m_names.find(name);
  if( i == m_names.end() )
    throw ConfigError("Field " + name + " not defined in fields section");
  return i->second;

  QF_STACK_POP
}

int DataDictionary::addXMLComponentFields( DOMDocument* pDoc, DOMNode* pNode,
                                            const std::string& msgtype,
                                            DataDictionary& DD,
                                            bool componentRequired )
{ QF_STACK_PUSH(DataDictionary::addXMLComponentFields)

  int firstField = 0;

  DOMAttributesPtr attrs = pNode->getAttributes();
  std::string name;
  if(!attrs->get("name", name))
    throw ConfigError("No name given to component");

  DOMNodePtr pComponentNode =
    pDoc->getNode("/fix/components/component[@name='" + name + "']");
  if(pComponentNode.get() == 0)
    throw ConfigError("Component not found");

  DOMNodePtr pComponentFieldNode = pComponentNode->getFirstChildNode();
  while(pComponentFieldNode.get())
  {
    if(pComponentFieldNode->getName() == "field"
       || pComponentFieldNode->getName() == "group")
    {
      DOMAttributesPtr attrs = pComponentFieldNode->getAttributes();
      std::string name;
      if(!attrs->get("name", name))
        throw ConfigError("No name given to field");
      int field = lookupXMLFieldNumber(pDoc, name);
      if( firstField == 0 ) firstField = field;


      std::string required = "Y";
          bool isRequired = true;
      if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

          if(isRequired && componentRequired)
      {
        addRequiredField(msgtype, field);
      }

      DD.addField(field);
      DD.addMsgField(msgtype, field);
    }
    if(pComponentFieldNode->getName() == "group")
    {
      DOMAttributesPtr attrs = pComponentFieldNode->getAttributes();
      std::string required = "Y";
          bool isRequired = true;
      if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

          addXMLGroup(pDoc, pComponentFieldNode.get(), msgtype, DD, isRequired);
    }
    RESET_AUTO_PTR(pComponentFieldNode,
      pComponentFieldNode->getNextSiblingNode());
  }
  return firstField;

  QF_STACK_POP
}


void DataDictionary::addXMLFASTGroup( DOMDocument* pDoc, DOMNode* pNode,
                                  const std::string& msgtype,
                                  DataDictionary& DD) throw( ConfigError )
{ QF_STACK_PUSH(DataDictionary::addXMLFASTGroup)

  DOMAttributesPtr attrs = pNode->getAttributes();
  int fieldSlot = 0;
  std::string name;
  if(!attrs->get("name", name))
    throw ConfigError("No name given to group");

  std::string presence = "mandatory";
  attrs->get("presence", presence);

  bool groupRequired = true;
  if ( presence == "optional" ) groupRequired = false;

  int group = 0;      // = lookupXMLFieldNumber( pDoc, name );
  int delim = 0;
  int field = 0;
  DataDictionary groupDD;
  DOMNodePtr node = pNode->getFirstChildNode();
      std::string groupName;
       std::string groupNum = "";
 if( node->getName() == "length" )
  {
      DOMAttributesPtr lenAttrs = node->getAttributes();
      if ( !lenAttrs->get("name", groupName) )
          throw ConfigError("No name given to group length field");
      if (!lenAttrs->get("id", groupNum) )
            throw ConfigError("No tag num given to group length");

      int grpNum = atol(groupNum.c_str());
      addFASTField(grpNum);
      addFASTFieldType(grpNum, XMLFASTTypeToType("uInt32"));
      addFASTFieldName(grpNum, groupName);
      groupDD.addFASTField( grpNum );
      if(groupRequired)
        groupDD.addRequiredField(msgtype, grpNum);
      group = grpNum;
      addTemplateID(groupNum, group);
      RESET_AUTO_PTR(node, node->getNextSiblingNode());

  }
 int tid = atol(groupNum.c_str());
  bool bMsgTypeFound = true;
  std::string msgType = "XYG";
  while(node.get())
  {
    int iField = 0;
    if( node->getName() != "sequence" )
    {
        AddXMLFASTField(pDoc, node.get(), bMsgTypeFound,
                     tid, msgType, groupRequired, fieldSlot, groupDD, iField, groupName);
    }
    else if( node->getName() == "sequence" )
    {

        addXMLFASTGroup( pDoc, node.get(), msgtype, groupDD);
    }
    if( delim == 0 ) delim = iField;
    RESET_AUTO_PTR(node, node->getNextSiblingNode());
  }

  if( delim ) DD.addGroup( msgtype, group, delim, groupDD );

  QF_STACK_POP
}




void DataDictionary::addXMLGroup( DOMDocument* pDoc, DOMNode* pNode,
                                  const std::string& msgtype,
                                  DataDictionary& DD, bool groupRequired, int tid )
{ QF_STACK_PUSH(DataDictionary::addXMLGroup)

  DOMAttributesPtr attrs = pNode->getAttributes();
  int fieldSlot = 0;
  std::string name;
  if(!attrs->get("name", name))
    throw ConfigError("No name given to group");
  int group = lookupXMLFieldNumber( pDoc, name );
  int delim = 0;
  int field = 0;
  DataDictionary groupDD;
  DOMNodePtr node = pNode->getFirstChildNode();
  while(node.get())
  {
    if( node->getName() == "field" )
    {
      field = lookupXMLFieldNumber( pDoc, node.get() );
      groupDD.addField( field );

      DOMAttributesPtr attrs = node->getAttributes();
      std::string required = "Y";
          bool isRequired = true;
      if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

          std::string fieldname = "none";
          if(!attrs->get("name", fieldname))
                  throw ConfigError("No name given to group's fieldname");

      if( isRequired )
      {
        groupDD.addRequiredField(msgtype, field);
      }
          if(tid)
          {
                  std::string value="";
                  if ( !attrs->get("value", value) )
                          value = "none";

                  std::string _operator = "";
                  if ( !attrs->get("operator", _operator) )
                          _operator = "none";

                  std::string ref = "";
                  if ( !attrs->get("ref", ref) )
                          ref = "none";

                  eFAST_TYPE FastType;
                  getFieldType(field, FastType);
                  eFAST_OP FastOperator;
                  getFieldOpearator(_operator, FastOperator);
                  FastTag ft(FastType, isRequired, FastOperator, tid, fieldSlot , field, value, ref, fieldname);
                  addMsgFieldTag(ft);
                  fieldSlot++;
          }
    }
    else if( node->getName() == "component" )
    {
      field = addXMLComponentFields( pDoc, node.get(), msgtype, groupDD, false );
    }
    else if( node->getName() == "group" )
    {
      field = lookupXMLFieldNumber( pDoc, node.get() );
      groupDD.addField( field );
      DOMAttributesPtr attrs = node->getAttributes();

          std::string required = "Y";
          bool isRequired = true;
      if (attrs->get("required", required))
                      (required == "N" || required == "n" )? isRequired  = false : isRequired  = true;

          if(isRequired && groupRequired)
      {
        groupDD.addRequiredField(msgtype, field);
      }
          std::string gtid;
          if(attrs->get("tid", gtid))
          {
                  if(tid)
                  {
                          std::string value="";
                          if ( !attrs->get("value", value) )
                                  value = "none";

                          std::string _operator = "";
                          if ( !attrs->get("operator", _operator) )
                                  _operator = "none";

                          std::string ref = "";
                          if ( !attrs->get("ref", ref) )
                                  ref = "none";

                          std::string fieldname = "none";
                          if(!attrs->get("name", fieldname))
                                  throw ConfigError("No name given to group's fieldname");

                          eFAST_TYPE FastType;
                          getFieldType(field, FastType);
                          eFAST_OP FastOperator;
                          getFieldOpearator(_operator, FastOperator);
                          FastTag ft(FastType, isRequired, FastOperator, tid, fieldSlot , field, value, ref, fieldname);
                          addMsgFieldTag(ft);
                          fieldSlot++;
                  }

                  addTemplateID(gtid, atoi(gtid.c_str()));
                  addXMLGroup(pDoc, node.get(), msgtype, groupDD, isRequired, atoi(gtid.c_str()));
          }
          else
                  addXMLGroup(pDoc, node.get(), msgtype, groupDD, isRequired);
    }
    if( delim == 0 ) delim = field;
    RESET_AUTO_PTR(node, node->getNextSiblingNode());
  }

  if( delim ) DD.addGroup( msgtype, group, delim, groupDD );

  QF_STACK_POP
}

TYPE::Type DataDictionary::XMLTypeToType( const std::string& type ) const
{ QF_STACK_PUSH(DataDictionary::XMLTypeToType)

  if ( m_beginString < "FIX.4.2" && type == "CHAR" )
    return TYPE::String;

  if ( type == "STRING" ) return TYPE::String;
  if ( type == "CHAR" ) return TYPE::Char;
  if ( type == "PRICE" ) return TYPE::Price;
  if ( type == "INT" ) return TYPE::Int;
  if ( type == "UINT" ) return TYPE::UInt;
  if ( type == "LONG" ) return TYPE::Long;
  if ( type == "ULONG" ) return TYPE::ULong;
  if ( type == "AMT" ) return TYPE::Amt;
  if ( type == "QTY" ) return TYPE::Qty;
  if ( type == "CURRENCY" ) return TYPE::Currency;
  if ( type == "MULTIPLEVALUESTRING" ) return TYPE::MultipleValueString;
  if ( type == "EXCHANGE" ) return TYPE::Exchange;
  if ( type == "UTCTIMESTAMP" ) return TYPE::UtcTimeStamp;
  if ( type == "BOOLEAN" ) return TYPE::Boolean;
  if ( type == "LOCALMKTDATE" ) return TYPE::LocalMktDate;
  if ( type == "DATA" ) return TYPE::Data;
  if ( type == "FLOAT" ) return TYPE::Float;
  if ( type == "PRICEOFFSET" ) return TYPE::PriceOffset;
  if ( type == "MONTHYEAR" ) return TYPE::MonthYear;
  if ( type == "DAYOFMONTH" ) return TYPE::DayOfMonth;
  if ( type == "UTCDATE" ) return TYPE::UtcDate;
  if ( type == "UTCDATEONLY" ) return TYPE::UtcDateOnly;
  if ( type == "UTCTIMEONLY" ) return TYPE::UtcTimeOnly;
  if ( type == "NUMINGROUP" ) return TYPE::NumInGroup;
  if ( type == "PERCENTAGE" ) return TYPE::Percentage;
  if ( type == "SEQNUM" ) return TYPE::SeqNum;
  if ( type == "LONGSEQNUM" ) return TYPE::LongSeqNum;
  if ( type == "LENGTH" ) return TYPE::Length;
  if ( type == "COUNTRY" ) return TYPE::Country;
  if ( type == "TIME" ) return TYPE::UtcTimeStamp;
  return TYPE::Unknown;

  QF_STACK_POP
}


TYPE::Type DataDictionary::XMLFASTTypeToType( const std::string& type ) const
{ QF_STACK_PUSH(DataDictionary::XMLFASTTypeToType)

  if ( type == "string" ) return TYPE::String;
  if ( type == "int32" ) return TYPE::Int;
  if ( type == "uInt32" ) return TYPE::UInt;
  if ( type == "int64" ) return TYPE::Long;
  if ( type == "uInt64" ) return TYPE::ULong;
  if ( type == "decimal" ) return TYPE::Float;
  return TYPE::Unknown;

  QF_STACK_POP
}
eFAST_TYPE DataDictionary::TypeToFastType( const TYPE::Type& type ) const
{ QF_STACK_PUSH(DataDictionary::TypeToFastType)

  if ( m_beginString < "FIX.4.2" && type == "CHAR" )
    return eFAST_TYPE_ASCII;


  if ( type == TYPE::String ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::Char ) return eFAST_TYPE_I32;
  if ( type == TYPE::Price ) return eFAST_TYPE_DECMIAL;
  if ( type == TYPE::Int ) return eFAST_TYPE_I32;
  if ( type == TYPE::UInt ) return eFAST_TYPE_U32;
  if ( type == TYPE::Long ) return eFAST_TYPE_I64;
  if ( type == TYPE::ULong ) return eFAST_TYPE_U64;
  if ( type == TYPE::Amt ) return eFAST_TYPE_I32;
  if ( type == TYPE::Qty ) return eFAST_TYPE_DECMIAL;
  if ( type == TYPE::Currency ) return eFAST_TYPE_I32;
  if ( type == TYPE::MultipleValueString ) return eFAST_TYPE_UNICODE;
  if ( type == TYPE::Exchange ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::UtcTimeStamp ) return eFAST_TYPE_ASCII;
  if ( type ==  TYPE::Boolean ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::LocalMktDate ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::Data ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::Float ) return eFAST_TYPE_DECMIAL;
  if ( type == TYPE::PriceOffset ) return eFAST_TYPE_I32;
  if ( type == TYPE::MonthYear ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::DayOfMonth ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::UtcDate ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::UtcDateOnly ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::UtcTimeOnly ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::NumInGroup ) return eFAST_TYPE_GROUP;
  if ( type == TYPE::Percentage ) return eFAST_TYPE_DECMIAL;
  if ( type == TYPE::SeqNum ) return eFAST_TYPE_U32;
  if ( type == TYPE::LongSeqNum ) return eFAST_TYPE_U64;
  if ( type == TYPE::Length ) return eFAST_TYPE_I32;
  if ( type == TYPE::Country ) return eFAST_TYPE_ASCII;
  if ( type == TYPE::UtcTimeStamp ) return eFAST_TYPE_ASCII;
  throw "Incorrect id";
  QF_STACK_POP
}

}
